export type ProgressSetting = {
  timing?: {
    delay?: number
    interval?: number
    auto?: boolean
  }
  target?: HTMLElement
  color?: {
    point?: string
    start?: string
    end?: string
    back?: string
  }
  width?: {
    initial?: string
    radius?: boolean
    autoRun?: string
    end?: string
  }
  height?: string
}
export function deepCopy<T>(data: T) {
  return JSON.parse(JSON.stringify(data))
}

export function RAF(callback: Function, timeout?: number, timer?: { timeout?: number }) {
  return new Promise<typeof RAF>((res, rej) => {
    try {
      if (timeout) {
        let timerTimeout = setTimeout(() => {
          requestAnimationFrame(() => {
            callback()
            res(RAF)
          })
        }, timeout)
        if (timer) {
          timer.timeout = timerTimeout
        }
      } else {
        requestAnimationFrame(() => {
          callback()
          res(RAF)
        })
      }
    } catch {
      rej()
    }
  })
}
/**
 * 默认设置
 */
const defaultSetting: ProgressSetting = {
  timing: {
    delay: 500,
    interval: 500,
    auto: true
  },
  color: {
    point: 'rgb(0, 255, 195)',
    start: 'rgb(0, 255, 195)',
    end: '#67c23a',
    back: 'none'
  },
  width: {
    initial: '20%',
    radius: true,
    autoRun: '100px',
    end: '20%'
  },
  height: '3px'
}

export class Progress {
  #target: HTMLElement = document.body
  #settingVal: ProgressSetting = deepCopy(defaultSetting)
  #back: HTMLElement | null = null
  #bar: HTMLElement = document.createElement('div')
  // dom display none
  #interval: number = 0
  #onStart: boolean = false
  #progress: number = 0
  // 开始状态条
  start() {
    if (!this.#back) {
      return
    }
    clearInterval(this.#interval)
    // 初始化
    this.#back.style.display = 'none'
    this.#bar.style.opacity = '1'
    this.#bar.style.width = '0px'
    this.#onStart = true
    this.#progress = 0
    // 下一帧开始展示组件
    RAF(() => {
      if (!this.#back) {
        return
      }
      this.#back.style.display = 'block'
    }).then((raf) => {
      // 继续下一帧
      raf(() => {
        // 如果现在还出去进入状态就初始化进度条长度
        if (this.#onStart) {
          this.#bar.style.width = this.#settingVal.width?.initial!
          // 自动动画 模拟进度
          if (this.#settingVal.timing?.auto) {
            this.#auto()
          }
        }
      })
    })
  }
  // 自动动画
  #auto() {
    this.#interval = setInterval(() => {
      this.#progress = this.#progress + 0.1
      if (this.#progress >= 1) {
        this.#progress = 1
      }
      this.to()
    }, this.#settingVal.timing?.interval)
  }
  //结束进度条
  end() {
    if (!this.#back) {
      return
    }
    clearInterval(this.#interval)
    this.#onStart = false
    RAF(() => {
      this.#bar.style.width = '100%'
      this.#bar.style.opacity = '0'
    }, this.#settingVal.timing?.delay).then(() => {
      // dom不显示
      let fun = () => {
        if (!this.#back) {
          return
        }
        if (this.#back && !this.#onStart) {
          this.#back.style.display = 'none'
        }
        this.#bar.removeEventListener('transitionend', fun)
      }
      this.#bar.addEventListener('transitionend', fun)
    })
  }
  /**
   * 让进度条去到百分之多少
   * @param percent 百分比 小数
   */
  to(percent?: number) {
    if (!this.#back && !this.#onStart) {
      return
    }
    if (!percent) {
      percent = this.#progress
    }
    this.#bar.style.width = `calc( ${this.#settingVal.width?.initial} + ( 100% - ${this.#settingVal.width?.initial} - ${this.#settingVal.width?.end}) * ${percent})`
  }
  constructor(setting?: ProgressSetting) {
    if (setting?.target) {
      this.el(setting.target)
    }
    // 初始化dom元素
    this.#back = document.createElement('div')
    this.#back.append(this.#bar)
    this.#target.append(this.#back)
    this.#back.style.cssText = `
        position: absolute;
        top: 0px;
        width: 100%;
        overflow: hidden;
        display: none;
        height: ${this.#settingVal.height};`
    this.#bar.style.cssText = `
        width: ${this.#settingVal.width?.initial};
        height: 100%;
        transition: ${this.#settingVal.timing?.delay}ms;
        background-color: ${this.#settingVal.color?.end};
        border-radius: calc( ${this.#settingVal.width?.radius ? this.#settingVal.height : '0px'} / 2 );
        background-image: linear-gradient(to right, ${this.#settingVal.color?.start}, ${this.#settingVal.color?.end});`
  }
  // 绑定el元素
  el(target: HTMLElement | string) {
    if (typeof target == 'string') {
      this.#target = document.querySelector(target) || document.body
    } else {
      this.#target = target
    }
    let style = getComputedStyle(this.#target)
    if (style.position == 'static') {
      this.#target.style.position = 'relative'
    }
  }
  // 销毁
  destroy() {
    if (!this.#back) {
      return
    }
    this.#back.remove()
    this.#back = null
  }
}
